#include "StdAfx.h"


Terrain::Terrain(Ogre::SceneManager* mSceneMgr, Ogre::Light* light)
{
	this->mSceneMgr = mSceneMgr;
	this->light = light;

	mTerrainGlobals = OGRE_NEW Ogre::TerrainGlobalOptions();

	mTerrainGroup = OGRE_NEW Ogre::TerrainGroup(mSceneMgr, Ogre::Terrain::ALIGN_X_Z, 513, 12000.0f);
    mTerrainGroup->setFilenameConvention(Ogre::String("Proba"), Ogre::String("dat"));
    mTerrainGroup->setOrigin(Ogre::Vector3(0,-242,0));
}

void Terrain::createTerrain(NxPhysicsSDK* mPhysicsSDK, NxScene* mNxScene)
{
	configureTerrainDefaults(light);

	for (long x = 0; x <= 0; ++x)
        for (long y = 0; y <= 0; ++y)
            defineTerrain(x, y);

	// sync load since we want everything in place when we start
    mTerrainGroup->loadAllTerrains(true);

	if (mTerrainsImported)
    {
        Ogre::TerrainGroup::TerrainIterator ti = mTerrainGroup->getTerrainIterator();
        while(ti.hasMoreElements())
        {
            Ogre::Terrain* t = ti.getNext()->instance;
            initBlendMaps(t);

			NxHeightFieldDesc heightFieldDesc; 
      heightFieldDesc.nbColumns = t->getSize(); 
      heightFieldDesc.nbRows = t->getSize(); 
      heightFieldDesc.convexEdgeThreshold = 0; 
	  heightFieldDesc.thickness = 0;
      heightFieldDesc.samples = new NxU32[(t->getSize()) * (t->getSize())]; 
      heightFieldDesc.sampleStride = sizeof(NxU32);  
      char* currentByte = (char*)heightFieldDesc.samples; 
      for (NxU32 row = 0; row < t->getSize(); row++) 
      {
         for (NxU32 col = 0; col < t->getSize(); col++) 
         {
            NxHeightFieldSample* currentSample = (NxHeightFieldSample*)currentByte; 
            currentSample->height =(NxI16)*t->getHeightData(row,t->getSize() - 1 - col);
            currentByte += heightFieldDesc.sampleStride;          
         }
      }
      NxHeightField* heightField = mPhysicsSDK->createHeightField(heightFieldDesc); 
      delete [] heightFieldDesc.samples; 
      NxHeightFieldShapeDesc heightFieldShapeDesc; 
      heightFieldShapeDesc.heightField = heightField; 
      heightFieldShapeDesc.heightScale = 1; 
      heightFieldShapeDesc.shapeFlags = NX_SF_FEATURE_INDICES; 
      heightFieldShapeDesc.rowScale = t->getWorldSize() / NxReal(t->getSize()-1); 
      heightFieldShapeDesc.columnScale = t->getWorldSize() / NxReal(t->getSize()-1); 
      heightFieldShapeDesc.materialIndexHighBits = 0;   
      heightFieldShapeDesc.holeMaterial = 2;
      NxActorDesc actorDesc; 
      assert(heightFieldShapeDesc.isValid());      
      actorDesc.shapes.pushBack(&heightFieldShapeDesc); 
      actorDesc.body = 0; 
      actorDesc.globalPose.t.setx(-t->getWorldSize() / 2); 
      actorDesc.globalPose.t.setz(-t->getWorldSize() / 2); 
      actorDesc.globalPose.t.sety(-239.39); 
      assert(actorDesc.isValid());  
      NxActor* actor = mNxScene->createActor(actorDesc);

        }
    }

	mTerrainGroup->freeTemporaryResources();
}
void Terrain::getTerrainImage(bool flipX, bool flipY, Ogre::Image& img)
{
	img.load("terrain.png", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
    if (flipX)
        img.flipAroundY();
    if (flipY)
        img.flipAroundX();
}
void Terrain::defineTerrain(long x, long y)
{
	Ogre::String filename = mTerrainGroup->generateFilename(x, y);
	if (Ogre::ResourceGroupManager::getSingleton().resourceExists(mTerrainGroup->getResourceGroup(), filename))
	{
		mTerrainGroup->defineTerrain(x, y);
	}
	else
	{
		Ogre::Image img;
		getTerrainImage(x % 2 != 0, y % 2 != 0, img);
		mTerrainGroup->defineTerrain(x, y, &img);
		mTerrainsImported = true;
	}

}


void Terrain::initBlendMaps(Ogre::Terrain* terrain)
{
	Ogre::TerrainLayerBlendMap* blendMap0 = terrain->getLayerBlendMap(1);
    Ogre::TerrainLayerBlendMap* blendMap1 = terrain->getLayerBlendMap(2);
    Ogre::Real minHeight0 = 70;
    Ogre::Real fadeDist0 = 40;
    Ogre::Real minHeight1 = 70;
    Ogre::Real fadeDist1 = 15;
    float* pBlend1 = blendMap1->getBlendPointer();
    for (Ogre::uint16 y = 0; y < terrain->getLayerBlendMapSize(); ++y)
    {
        for (Ogre::uint16 x = 0; x < terrain->getLayerBlendMapSize(); ++x)
        {
            Ogre::Real tx, ty;
 
            blendMap0->convertImageToTerrainSpace(x, y, &tx, &ty);
            Ogre::Real height = terrain->getHeightAtTerrainPosition(tx, ty);
            Ogre::Real val = (height - minHeight0) / fadeDist0;
            val = Ogre::Math::Clamp(val, (Ogre::Real)0, (Ogre::Real)1);
 
            val = (height - minHeight1) / fadeDist1;
            val = Ogre::Math::Clamp(val, (Ogre::Real)0, (Ogre::Real)1);
            *pBlend1++ = val;
        }
    }
    blendMap0->dirty();
    blendMap1->dirty();
    blendMap0->update();
    blendMap1->update();
}
//-------------------------------------------------------------------------------------
void Terrain::configureTerrainDefaults(Ogre::Light* light)
{
	// Configure global
    mTerrainGlobals->setMaxPixelError(8);
    // testing composite map
    mTerrainGlobals->setCompositeMapDistance(3000);
 
    // Important to set these so that the terrain knows what to use for derived (non-realtime) data
    mTerrainGlobals->setLightMapDirection(light->getDerivedDirection());
    mTerrainGlobals->setCompositeMapAmbient(mSceneMgr->getAmbientLight());
    mTerrainGlobals->setCompositeMapDiffuse(light->getDiffuseColour());
 
    // Configure default import settings for if we use imported image
    Ogre::Terrain::ImportData& defaultimp = mTerrainGroup->getDefaultImportSettings();
    defaultimp.terrainSize = 513;
    defaultimp.worldSize = 12000.0f;
    defaultimp.inputScale = 600;
    defaultimp.minBatchSize = 33;
    defaultimp.maxBatchSize = 65;
    // textures
    defaultimp.layerList.resize(3);
    defaultimp.layerList[0].worldSize = 100;
    defaultimp.layerList[0].textureNames.push_back("Sky.jpg");
    //defaultimp.layerList[0].textureNames.push_back("clouds.jpg");
    defaultimp.layerList[1].worldSize = 30;
    defaultimp.layerList[1].textureNames.push_back("Sky.jpg");
    //defaultimp.layerList[1].textureNames.push_back("clouds.jpg");
    defaultimp.layerList[2].worldSize = 200;
    defaultimp.layerList[2].textureNames.push_back("Sky.jpg");
    //defaultimp.layerList[2].textureNames.push_back("growth_weirdfungus-03_normalheight*.dds");
}

void Terrain::destroy()
{
	OGRE_DELETE mTerrainGroup;
    OGRE_DELETE mTerrainGlobals;
}
Terrain::~Terrain(void)
{
}
